DllTest - sample code to call the Runtime Module in VB.NET
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This project is written in Visual Studio 2002 but will work in more recent versions of Visual Studio
(it will upgrade the Project to the latest version. If prompted you should also upgrade the .NET
framework the project requires).

The main source files in the project are:

File name       Description
Form1.vb        main source code file for VB.NET
dris.vb         contains the DRIS structure and low-level functions to manipulate it.

The best approach is to compile the sample code and see how it works and then to take the appropriate code
and apply it to your own project. You should include the dris.vb file in your project and use/modify which
ever functions from form1.vb you feel are appropriate. The dris.vb file should not be modified.

The sample code contains 11 functions. You will not need to use all these functions in your code. Just use
which ever functions are most appropriate and customise in your own way. The sample code is just a guide.
You should implement the protection in a stronger way using the techniques described in the
"Increasing your Protection" chapter of the manual.

Code marked with !!!! are places where you should customise the sample code so that it will work properly:

* Change the MY_SDSN value to the value of your SDSN
* Change the MY_PRODCODE value to the Product Code in the dongle
* Change the MyAlgorithm code (if you call a user algorithm)
* Change the CryptDRIS code (if you encrypt the DRIS)
* Change the CryptApiData (if you encrypt Data you send to our API)
* Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm)

You will also probably want to replace our error messages with your own. However, you should still
display or log any error codes returned by the protection check otherwise you will not be able to
identify the cause of the error. (You can look up error codes in our knowledge base: microcosm.com/kb).

For users of Visual Studio 2005 or higher, the default setting for projects is to compile for the Target
Platform "Any". This means that on 32-bit Windows, your code will run as 32-bit code (and needs to call
dpwin32.dll) and under 64-bit Windows your code will run as 64-bit code (and needs to call dpwin64.dll).
The sample code works this out automatically. If you select the target platform as "x86" then it will
always be 32-bit and so you only need to use dpwin32.dll. If you select "x64" then your code will be
64-bit and you only need to use dpwin64.dll.

Note - as you are using the API method in this sample you should protect dpwin32.dll and/or dpwin64.dll
and not your program. Because your program is linked to the DLL it is protected. You can also protect
your program with the Shell Method should you wish.

Note - if you are compiling for the Platform target "Any" (and therefore need to protect both dpwin32.dll
and dpwin64.dll) then you will probably want to protect these modules to the same licence so that they share
a common set of protection parameters.

Make sure you remember to do the following:

1) Insert the following namespaces in your code file:
Imports System.Runtime.InteropServices

2) Insert the dris.vb file in your project.

3) The protected dpwin32.dll (dpwin64.dll) should be output to the folder that contains your EXE file.
Otherwise the message "Unable to open DLL (dpwin32.dll)" or System.DllNotFoundException error will appear
when you run DllTest. Unfortunately, when the system displays these exceptions, it gives the choice of
"Continue" which will return from the program assuming it returned success - and thereby bypassing the
protection check. To combat this we have added the Protection_Err exception handler to handle exceptions.
This behaviour appears to be unique to VB.NET.

If you wish you can rename dpwin32.dll (dpwin64.dll) to a name of your choice. In this case you will need to
modify the dll name in the dris.vb file.

Note - VB.NET is an interpreted language and so it is easier to decompile than other languages. You can
improve security if you use an obfuscator to obfuscate your code. Or - even better - you could use the
Shell Method to protect your executable. This encrypts your code (making it impossible to decompile).

Note for using strings in DRIS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To set the alt_licence_name field and read the prodcode field in the DRIS you need to use the
SetAltLicenceName and GetProductCode functions. You can use other fields directly, e.g. dris.sdsn

Notes on Debugging 64-bit Code
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When you use the 64-bit runtime module (dpwin64.dll) to protect your software the anti-debug code is so
strong that if you are debugging your code, after the call DDProtCheck then it will crash with an SEH
exception. If you want to be able to debug your code then you can setup your project so that your code
calls the debug module (dpwin64debug.dll) in your "debug" build and the standard module (dpwin64.dll)
in your release build. You can do this by modifying the declaration of DDProtCheck64 in dris.vb like this:

#if DEBUG		' debug module
   Declare Function DDProtCheck64 Lib "dpwin64debug.dll" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer
#else			' standard module
   Declare Function DDProtCheck64 Lib "dpwin64.dll" Alias "DDProtCheck" (ByRef mydris As DRIS, ByVal data() As Byte) As Integer
#endif

Note - the debug module has the following restrictions:

1) It will not correctly start a network user (network dongles only). However, other than that the protection
   check will function correctly and return success.
2) You will not be able to encrypt the DRIS. (If you do encrypt the DRIS in your release build then you
   should make sure that CryptDRIS does not get called in your debug build).
3) The protection check will take slightly longer than normal.
4) The DDGetNetUserList function will return error 428 (not implemented).
5) A temporary subprocess is created which may be (falsely) detected as malicious by anti-virus programs.

This behaviour does not occur in 32-bit code, so if you are using dpwin32.dll then you can debug your code.

Special Note for using Algorithms in VB.NET
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The algorithms are calculated using 32-bit integers (Integer in vb.net). It is quite possible for the
MyAlgorithm and MyRWAlgorithm functions to overflow if the values provided are too big. In the dongle the
algorithms can never overflow - if the answer is too big then the high part of the answer is ignored.
In practical terms:

When you are using the r/w algorithm it is best not to pass random 32-bit integers. It is better to restrict
the variables to 24-bit to avoid the possibility of overflows. You can see this implemented in the MyRWAlgorithm
and WriteBytesEnc function, for example.

You can also use this technique with the user algorithms. Another option in MyAlgorithm is to convert each input
to 64-bit, apply the algorithm and then convert back to 32-bit to return the answer. 

When using a user algorithm it will behave exactly as the corresponding MyAlgorithm function will in VB
except it will not give overflow errors.

Important Note for UWP app Developers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Universal Windows Platform (UWP) application (previously called Windows Store Apps or Metro Apps) are not
compatible with Lite or Plus dongles because the restrictions imposed by these applications. However, you
can protect these Apps with network dongles (because the restrictive access is performed by the non-UWP
DinkeyServer process). If you do this you will need to enable the "Private Networks (Client and Server)"
Capability in your package manifest.

.NET Core / .NET 5+
~~~~~~~~~~~~~~~~~~~

The sample code provided also works with .NET Core. However, .NET Core also supports Linux and macOS as well
as other platforms. If you want to support these OS then please replace dris.vb with dris_dotnetcore.vb.
The files are very similar but dris_dotnetcore.vb will load the relevant native runtime module (dpwin32.dll
under 32-bit Windows; dpwin64.dll under 64-bit Windows; dplin64.so under Linux OS; dpmac64debug.dylib under
macOS - unfortunately the release module is not compatible with the .NET Core framework so you have to use
the debug one. This also means that our solution is not compatible with ARM-based macOS  - because the debug
modules do not exist).

If you are using .NET Core version earlier than 3.0 then Windows.Forms are not supported and you will have to
replace the MessageBox.Show lines with Console.WriteLine.

The Shell Method is compatible with .NET Core Console, Windows.Forms and WPF applications. It is supported
under Windows and Linux but not macOS. It is only supported for .NET Core version 3.0 or higher. If you are
using the Shell Method then you should protect your compiled dll and not the "appHost" (this is a native
executable which is just a stub program that loads the assemblies in your dll). Also do not use "dotnet run"
to launch your application - it will run the unprotected version. Either launch the executable or run using
"dotnet <program.dll>".

If you publish a "single-file executable" file then although this file can be protected we do not recommend
it because it is not secure. (The single-file executable just comprises a stub loader with your compiled
assemblies and configuration files appended to the end of the executable. These files are just considered as
data appended to the executable file in a custom format and therefore are not protected. When you shell
protect your executable you are just protecting the loader but not your assemblies). Instead you need to
build your code and then add protection before publishing. You should protect your assemblies in the obj
directory (and in the platform type you specified) e.g. obj/Release/net5.0/win-x64, because the publish
process takes your assemblies from this location when it builds the single-file executable. You will also
need to distribute all the extra files that DinkeyAdd generates. e.g. <file>.dp64.dll.

If you publish using the ReadytoRun compilation this will not work because it includes mixtures of .NET
assemblies and native code and the .NET Shell Method does not support that.

Visual Studio Installer Projects Extension
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You can use this extension to create a project in your solution that will create an installation program / msi
file. Please note that after your application has been built you need to protect it with DinkeyAdd before you
can invoke the installer project. You can do this manually by building your application project (not the entire
solution); then adding protection to your application using DinkeyAdd; then building your installer project.
Or you can automate this by executing DinkeyAddCmd as a post-build step. For example:
"c:\program files (x86)\Dinkey Pro 7.6.0\DinkeyAdd\DinkeyAddCmd.exe"  c:\adir\mydapf.dapfj  /a2

Note - if you specify "primary output" in your installer project then it will take the files from
obj\Release\net5.0 (for example), rather than bin\Release\net5.0. So, you need to add protection to your files
in this folder.

Note - if you use the API Method you will also need to include the protected runtime modules that you use
(e.g. dpwin64.dll). If you use the Shell Method you will also need to include in your installer project all
of the output files mentioned by DinkeyAdd. e.g. <application_name>.dp64.dll
